#include "factory.h"
//服务器端接收客户端上传的文件
int do_puts(int tran_fd,train_state_t *ct,Client_State_t *p)
{
    printf("start uploading!!\n");
    train_t t;
    int ret,size;
    int data_len;
    char r_buf[1000]={0};
    char file_path[100]="./";
    char md5_str[128]={0};
    ct->cmd_type=PUTS;
    ct->data_len=sizeof(train_state_t);
    ret=send_n(tran_fd,&ct->data_len,sizeof(int));//发送PUTS长度
    SELFFUNC_ERR_CHECK(ret,"send_n");
    ret=send_n(tran_fd,&ct,4+ct->data_len);//发送PUTS内容
    SELFFUNC_ERR_CHECK(ret,"send_n");
    bzero(t.buf,sizeof(t.buf));
    t.data_len=sizeof(ct->offset);
    strcpy(t.buf,(char *)ct->offset);
    ret=send_n(tran_fd,&t.data_len,sizeof(int));//发送offset长度
    SELFFUNC_ERR_CHECK(ret,"send_n");
    ret=send_n(tran_fd,&t,4+t.data_len);//发送offset内容
    SELFFUNC_ERR_CHECK(ret,"send_n");
    strcat(file_path,ct->file_name);
    Compute_file_md5(file_path,md5_str);//得到文件md5码
    printf("%s's md5 is and sengding:%s\n",ct->file_name,md5_str);
    t.data_len=strlen(md5_str);//MD5码长度装在火车头
    strcpy(t.buf,md5_str);//MD5码内容装在火车头
    ret=send_n(tran_fd,&t.data_len,sizeof(int));//发送MD5码长度
    SELFFUNC_ERR_CHECK(ret,"send_n");
    ret=send_n(tran_fd,&t,4+t.data_len);//发送MD5码内容
    SELFFUNC_ERR_CHECK(ret,"send_n");
    bzero(t.buf,sizeof(t.buf));
    if(-1==ret)
    {
        printf("sendding wrong!\n");

    }
    bzero(r_buf,sizeof(r_buf));
    ret=recv_n(tran_fd,&data_len,sizeof(int));//接收md5码验证结果
    SELFFUNC_ERR_CHECK(ret,"recv_n");
    if(data_len==0)//MD5码已经有了，即服务器端已有此文件
    {
        printf("%s exit\n",ct->file_name);
        return 0;
    }
    else
    {
        t.data_len=strlen(ct->file_name);//文件名长度装在火车头
        strcpy(t.buf,ct->file_name);//将文件内容装在火车车厢
        ret=send_n(tran_fd,&t.data_len,sizeof(int));//发送文件名长度
        SELFFUNC_ERR_CHECK(ret,"send_n");
        ret=send_n(tran_fd,&t,4+t.data_len);//发送文件名
        SELFFUNC_ERR_CHECK(ret,"send_n");
        bzero(t.buf,sizeof(t.buf));
        if(-1==ret)
        {
            printf("sendding worning\n");
        }
        int fd=open(ct->file_name,O_RDONLY);
        ERROR_CHECK(fd,-1,"open");
        //发送文件大小
        struct stat buf;
        ret=stat(ct->file_name,&buf);
        ERROR_CHECK(ret,-1,"stat");
        t.data_len=sizeof(buf.st_size);
        memcpy(t.buf,&buf.st_size,sizeof(buf.st_size));
        ret=send_n(tran_fd,&t,4+t.data_len);
        SELFFUNC_ERR_CHECK(ret,"send_n");
        bzero(t.buf,sizeof(t.buf));
        if(-1==ret)
        {
            printf("sendding wrong!\n");
        }
        //发送文件内容
        void* p=mmap(NULL,buf.st_size,PROT_READ,MAP_SHARED,fd,0);
        ERROR_CHECK(p,(void*)-1,"mmap");
        ret=send_n(tran_fd,p,buf.st_size);
        SELFFUNC_ERR_CHECK(ret,"send_n");
        bzero(t.buf,sizeof(t.buf));
        if(-1==ret)
        {
            printf("sendding wrong!\n");
        }
        printf("Send successed!\n");
        t.data_len=0;
        munmap(p,buf.st_size);
        return 0;
    }
}

//服务器端将文件发送给客户端
int do_gets(int tran_fd,train_state_t *ct,Client_State_t *p)
{
    printf("start downloading!!\n");
    train_t t;
    int ret,size;
    int data_len;
    char r_buf[1000]={0};
    char buf[1000]={0};
    char file_path[100]="./";
    ct->cmd_type=GETS;
    ct->data_len=sizeof(train_state_t);
    ret=send_n(tran_fd,&ct->data_len,sizeof(int));//发送GETS长度
    SELFFUNC_ERR_CHECK(ret,"send_n");
    ret=send_n(tran_fd,&ct,4+ct->data_len);//发送GETS内容
    SELFFUNC_ERR_CHECK(ret,"send_n");
    bzero(t.buf,sizeof(t.buf));
    //判断offset应该是多少
    strcat(file_path,ct->file_name);
    int test_fd=open(file_path,O_RDWR);
    if(test_fd==-1)//不存在该文件
    {
        ct->offset=0;
    }
    else//存在该文件，记录偏移值
    {
        long data_count=0;
        long data_total=0;
        char data_buf[4096]={0};
        while(1)
        {
            bzero(data_buf,sizeof(data_buf));
            data_count=read(test_fd,data_buf,sizeof(data_buf));
            if(data_count==0)
            {
                break;
            }
            else
            {
                data_total+=data_count;
            }
        }
        ct->offset=data_total;
    }
    t.data_len=sizeof(ct->offset);
    strcpy(t.buf,(char *)ct->offset);
    ret=send_n(tran_fd,&t.data_len,sizeof(int));//发送offset长度
    SELFFUNC_ERR_CHECK(ret,"send_n");
    ret=send_n(tran_fd,&t,4+t.data_len);//发送offset内容
    SELFFUNC_ERR_CHECK(ret,"send_n");
    ret=recv_n(tran_fd,&data_len,4);//接文件名长度
    SELFFUNC_ERR_CHECK(ret,"recv_n");
    ret=recv_n(tran_fd,buf,data_len);//接文件名
    SELFFUNC_ERR_CHECK(ret,"recv_n");
    int fd=open(buf,O_WRONLY|O_CREAT,0666);
    ERROR_CHECK(fd,-1,"open");
    //接受文件大小
    ret=recv_n(tran_fd,&data_len,4);
    SELFFUNC_ERR_CHECK(ret,"recv_n");
    //download_size当前大小，last_size是上次大小
    off_t file_size,download_size=0,last_size=0;
    ret=recv_n(tran_fd,&file_size,data_len);//接文件大小
    SELFFUNC_ERR_CHECK(ret,"recv_n");
    printf("file_size=%ld\n",file_size);
    //接收文件内容
    ret=ftruncate(fd,file_size);
    ERROR_CHECK(ret,-1,"ftruncate");
    void* p1=mmap(NULL,file_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    ERROR_CHECK(p1,(void*)-1,"mmap");
    ret=recv_n_show(tran_fd,p1,file_size);
    SELFFUNC_ERR_CHECK(ret,"recv_n");
    ret=munmap(p1,file_size);
    ERROR_CHECK(ret,-1,"munmap");
}

//循环接收数据，直到接收到自己想要数量
int recv_n(int sfd,void* buf,int data_len)
{
    char *p=(char*)buf;
    int total=0,ret;
    while(total<data_len)
    {
        ret=recv(sfd,p+total,data_len-total,0);
        total+=ret;
    }
    return 0;
}


//循环发送数据，直到发送到自己想要数量
int send_n(int sfd,void* buf,int data_len)
{
    char *p=(char*)buf;
    int total=0,ret;
    while(total<data_len)
    {
        ret=send(sfd,p+total,data_len-total,0);
        if(-1==ret)//代表对端断开了
        {
            return -1;
        }
        total+=ret;
    }
    return 0;
}

//循环接收数据，能够显示接收数据进度
int recv_n_show(int sfd,void* buf,int data_len)
{
    char *p=(char*)buf;
    int total=0,ret;
    off_t slice_size=data_len/10000;//文件的万分之一大小
    off_t last_size=0;//上一次大小
    while(total<data_len)
    {
        ret=recv(sfd,p+total,data_len-total,0);
        if(ret==-1)//对端断开
        {
            return -1;
        }
        total+=ret;
        if(total-last_size>slice_size)//打印进度
        {
            printf("%6.2lf%%\r",(double)total/data_len*100);
            fflush(stdout);
            last_size=total;
        }
    }
    printf("100.00%%\n");
    return 0;
}
//注册、监控
int epoll_add(int epfd,int fd)
{
    struct epoll_event event;
    event.data.fd=fd;//注册
    event.events=EPOLLIN;//是否可读
    int ret=epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
    ERROR_CHECK(ret,-1,"epoll_ctl_add");
    return 0;
}